<?php
/**
 * Created by Zhy
 * User: Zhy
 * Date: 2021/3/24
 * Time: 10:24
 */

namespace app\api\controller;


use app\common\service\QueueService;
use think\Cache;
use think\cache\driver\Redis;
use think\Db;

class Drillmatch extends Base
{
    public $date_time;
    public $user_id;
    public $redis;
    public $temp_start_cross_points; //船只经过起始线时在起始线的点
    public $cross_distance = 8; // 判定绕标通过距离
    
    public function __construct()
    {
        $this->date_time = date('Y-m-d H:i:s');
        $this->user_id = input('user_id');
        $this->redis = new Redis();
    }
    
    //******************************************    设备采集端  start
    /**
     * 添加浮点设备
     * @param $app_sb_id   设备ID，唯一
     * @return {app_sb_id,app_id,app_number,app_ercode}
     */
    public function addDevice()
    {
        $app_sb_id = input('app_sb_id'); // 唯一表示
        if (empty($app_sb_id)) {
            return json(array('status' => 100, 'msg' => '设备id不能为空'));
        }
        $device_info = Db::table('up__sensor')
            ->where('app_sb_id', $app_sb_id)
            ->find();
        if (!$device_info) {
            $number = rand(1000, 9999);
            $app_id = $this->getNumber($number);
            $qrcode_url = $this->createQRcode($app_id);
            $data = [
                'app_sb_id' => $app_sb_id,
                'app_id' => $app_id,
                'app_number' => $app_id,
                'app_ercode' => $qrcode_url
            ];
            $res = Db::table('up__sensor')->insert($data);
            if ($res) {
                $device_info = $data;
            } else {
                return json(array('status' => 100, 'msg' => '绑定失败，请刷新重试！'));
            }
        }
        return json(array('status' => 200, 'msg' => $device_info));
    }
    
    /**
     * 刷新浮点设备
     * @param $app_sb_id   设备ID，唯一标识
     * @return {app_sb_id,app_id,app_number,app_ercode}
     */
    public function updtDevice()
    {
        $app_sb_id = input('app_sb_id');
        if (empty($app_sb_id)) {
            return json(array('status' => 100, 'msg' => '设备id不能为空'));
        }
        
        $number     = rand(1000, 9999);
        $app_id     = $this->getNumber($number);
        $qrcode_url = $this->createQRcode($app_id);
        $data       = [
            'app_sb_id'  => $app_sb_id,
            'app_id'     => $app_id,
            'app_number' => $app_id,
            'app_ercode' => $qrcode_url
        ];
        
        $device_info = Db::table('up__sensor')
            ->where('app_sb_id', $app_sb_id)
            ->find();
        if ($device_info) {
            Db::table('up__sensor')->where('app_sb_id', $app_sb_id)->delete();
        }
        $res = Db::table('up__sensor')->insert($data);
        if ($res) {
            $device_info = $data;
        } else {
            return json(array('status' => 100, 'msg' => '绑定失败，请刷新重试！'));
        }
        return json(array('status' => 200, 'msg' => $device_info));
    }
    
    /**
     * 更新、上传浮标设备位置
     * @param $lat    纬度
     * @param $lon    精度
     * @param $sensor_id    设备编号
     * @return {app_sb_id,app_id,app_number,app_ercode}
     */
    public function updBuoyDevice()
    {
//        header("Access-Control-Allow-Origin: *");
        $lon = input('lon');
        $lat = input('lat');
        $sensor_id = input('id');
        //============= 设备定位，改动部分，用于设备定位   start  ==================//
//        $app_sb_id = input('app_sb_id');
        
        //****  高德
//        $data['lat']       = $lon;
//        $data['lon']       = $lat;
        //****  百度
        // 百度坐标系换算
//        $gps = new Gps();
//        $new_gps = $gps->delta($lon, $lat);
//        $new_lat = $lat + $new_gps['lon'];
//        $new_lon = $lon + $new_gps['lat'];
//        $app_id = Db::table('up__sensor')
//            ->where('app_sb_id', $app_sb_id)
//            ->value('app_id');
//        $data['sensor_id'] = $app_id;
//        $data['lat']       = $new_lon;
//        $data['lon']       = $new_lat;
        //============  设备定位，改动部分，用于设备定位    end  ==================//
        $data['type']      = 2;
        //===============  手机定位
        $data['lon']       = $lon;
        $data['lat']       = $lat;
        $data['sensor_id'] = $sensor_id;
        
        if (!$data['sensor_id'] || !$data['lat'] || !$data['lat']) {
            return json(array('status' => 100, 'msg' => "参数不全！"));
        }
        $data['create_time'] = microtime(true);
        // 每次更新都同步到redis，下次取的时候，直接从redis取
        $this->redis->set($data['sensor_id'], json_encode($data));
        Db::table('up_sailboat_drill_match_origin')->insert($data);
        return json(array('status' => 200, 'msg' => "success"));
    }
    //******************************************    设备采集端  end
    
    //******************************************    运动员端  start
    /**
     * 运动员端训练赛设置同步
     * @return \think\response\Json
     * drill_id     训练ID
     */
    public function player(){
        $drill_id = input('drill_id');
        // 参数展示
        $dt = Db::table('up_sailboat_drill_turns')
            ->where('dt_drill_id', $drill_id)
            ->order('dt_id desc')
            ->find();
//        $data = json_decode($this->redis->get('turns_' . $dt['dt_id']), true);
        // 名次信息
        $ranking = Db::table('up_sailboat_drill_match_user_detail')
            ->where(['dmd_dt_id' => $dt['dt_id'], 'dmd_user_id' => $this->user_id])
            ->field('dmd_status, dmd_next_distance, dmd_ranking, dmd_to_first_distance, dmd_to_prior_distance, dmd_speed, dmd_to_finish_distance')
            ->find();
        return json(['status' => 200, 'msg' => $dt, 'ranking' => $ranking]);
    }
    
    /**
     * 更新、上传船只设备位置
     * @param $lat
     * @param $lon
     * @param $user_id
     * @return {app_sb_id,app_id,app_number,app_ercode}
     */
    public function updBoatDevice()
    {
        $data['type'] = 5;
        $data['sensor_id'] = 'drill_' . $this->user_id;
        $data['lat']       = input('lat');
        $data['lon']       = input('lon');
        if (!$data['sensor_id'] || !$data['lat'] || !$data['lon']) {
            return json(array('status' => 100, 'msg' => "参数不全！"));
        }
        $data['create_time'] = microtime(true);
        $this->redis->set($data['sensor_id'], json_encode($data));
        Db::table('up_sailboat_drill_match_origin')->insert($data);
        return json(array('status' => 200, 'msg' => "success"));
    }
    //******************************************    运动员端  end
    /**
     * 教练端------发起训练赛
     * @return \think\response\Json
     * drill_id       训练ID
     * dm_type        训练赛类型
     * dm_lon         教练定位精度
     * dm_lat         教练定位纬度
     */
    public function createDrillMatch(){
        $drill_id = input('drill_id');
        // 训练赛类型  1 练习赛  2 起航练习  3 单舷驶  4 起航线停船训练  5 8字标追逐   6 迎顺风追逐   7 换舷训练   8 360训练
        $dm_type = input('dm_type');
        $dm_lon = input('dm_lon'); // 教练定位精度
        $dm_lat = input('dm_lat'); // 教练定位纬度
        
        // 训练信息
        $drill = Db::table('up_sailboat_drill')
            ->where('drill_id', $drill_id)
            ->field('drill_join_user_id, drill_create_user_id')
            ->find();
        // 参加训练赛的运动员
        $join_user_arr = explode(',', trim($drill['drill_join_user_id'], ','));
        
        Db::startTrans();
        try{
            // 修改训练为训练赛
            Db::table('up_sailboat_drill')->where('drill_id', $drill_id)->setField('drill_is_match', 2);
            
            // 创建训练赛
            $dm_id = Db::table('up_sailboat_drill_match')
                ->insertGetId([
                    'dm_drill_id' => $drill_id,
                    'dm_type' => $dm_type,
                    'dm_create_user_id' => $drill['drill_create_user_id'],
                    'dm_create_time' => microtime(true),
                    'dm_lon' => $dm_lon,
                    'dm_lat' => $dm_lat
                ]);
            
            // 添加到训练赛轮次表，首次添加，默认选择第0轮
            $dt_id = Db::table('up_sailboat_drill_turns')
                ->insertGetId([
                    'dt_dm_id' => $dm_id,
                    'dt_drill_id' => $drill_id,
                    'dt_turns' => 0
                ]);
            
            foreach($join_user_arr as $k => $v){
                $color = randrgb();
                // 入队员表
                Db::table('up_sailboat_drill_match_user')
                    ->insert([
                        'du_user_id'    => $v,
                        'du_dm_id'      => $dm_id,
                        'du_drill_id'   => $drill_id,
                        'du_color'      => $color
                    ]);
    
                // 入设备绑定表
                Db::table('up_sailboat_drill_match_sensor_device')
                    ->insert([
                        'dms_name' => $v,
                        'dms_sensor_id' => 'drill_' . $v,
                        'dms_dm_id' => $dm_id,
                        'dms_dt_id' => $dt_id,
                        'dms_type' => 5
                    ]);
                
                // 插入运动员轮次明细表
                Db::table('up_sailboat_drill_match_user_detail')
                    ->insert([
                        'dmd_dm_id' => $dm_id,
                        'dmd_dt_id' => $dt_id,
                        'dmd_user_id' => $v,
                        'dmd_sensor_id' => 'drill_' . $v
                    ]);
                
                // 队员定位
                $this->sensor_arr[$k]['drill_' . $v] = json_decode($this->redis->get('drill_' . $v), true);
                $this->sensor_arr[$k]['color'] = $color;
                $this->sensor_arr[$k]['uid'] = $v;
            }
            
            $this->sensor_arr['dm_id'] = $dm_id;
            $this->sensor_arr['dm_lon'] = $dm_lon;
            $this->sensor_arr['dm_lat'] = $dm_lat;
            $this->sensor_arr['dt_id'] = $dt_id;
            
            // 将轮次信息存到redis
            $turns = Db::table('up_sailboat_drill_turns')->where('dt_id', $dt_id)->find();
            $this->redis->set('turns_' . $dt_id, json_encode($turns));
            
            Db::commit();
            return json(['status' => 200, 'msg' => $this->sensor_arr]);
        }catch(\Exception $e){
            Db::rollback();
            return json(['status' => 0, 'msg' => $e->getMessage()]);
        }
    }
    
    /**
     * 用于判断该训练有没有开启训练赛
     * @return \think\response\Json
     * drill_id     训练ID
     */
    public function isBeginDrillMatch(){
        $drill_id = input('drill_id');
        // 是否有开启训练赛
        $isBegin = Db::table('up_sailboat_drill')
            ->where('drill_id', $drill_id)
            ->field('drill_is_match, drill_call_id')
            ->find();
        // 该运动员所在分组
        $sg = Db::table('up_sailboat_drill_group')
            ->where('sg_drill_user_ids', 'like', "%,$this->user_id,%")
            ->where('sg_drill_id', $drill_id)
            ->field('sg_id')
            ->find();
        return json(['status' => 200, 'msg' => $isBegin, 'user_zu' => $sg]);
    }
    
    /**
     * 用于判断该教练有没有未开始或者进行中的训练赛
     * @return \think\response\Json
     * drill_id     训练ID
     */
    public function haveDrillMatch(){
        $drill_id = input('drill_id');
        $have = Db::table('up_sailboat_drill_match')
            ->where(['dm_drill_id' => $drill_id, 'dm_create_user_id' => $this->user_id])
            ->field('dm_type, dm_status')
            ->order('dm_id desc')
            ->find();
        if($have){
            $dt = Db::table('up_sailboat_drill_turns')
                ->where('dt_drill_id', $drill_id)
                ->field('dt_id')
                ->order('dt_id desc')
                ->find();
            $have['dt_id'] = $dt['dt_id'];
        }
        return json(['status' => 200, 'msg' => $have]);
    }
    
    /**
     * 起航旗、信号旗、航线图
     * @return \think\response\Json
     */
    public function flagList(){
        // 起航旗
        $start = Db::table('up_setsail_flag')->field('sf_id, sf_image')->select();
        // 航线图
        $sail_image = Db::table('up_match_sail_image')->field('msi_id, msi_image')->select();
        // 信号旗
        $signal = Db::table('up_flag_signal')->field('fs_id, fs_image')->select();
        $data['start'] = $start;
        $data['sail_image'] = $sail_image;
        $data['signal'] = $signal;
        return json($data);
    }
    
    /**
     * 更新倒计时时间
     * @return bool|\think\response\Json
     * dt_id     轮次ID
     * dt_count_down    倒计时时间，单位秒
     */
    public function setCountdown(){
        $dt_id = input('dt_id'); // 轮次ID
        $dt_count_down = input('dt_count_down'); // 选择的倒计时时长，单位秒
        $turns = json_decode($this->redis->get('turns_' . $dt_id), true);
        if($turns['dt_count_down'] == $dt_count_down){
            return json(['status' => 200, 'msg' => $turns]);
        }else{
            $res = Db::table('up_sailboat_drill_turns')->where('dt_id', $dt_id)->setField('dt_count_down', $dt_count_down);
            if($res){
                $turns['dt_count_down'] = $dt_count_down;
                $this->redis->set('turns_' . $dt_id, json_encode($turns));
                return json(['status' => 200, 'msg' => $this->pageDisplay($dt_id)]);
            }else{
                return json(['status' => 0, 'msg' => '编辑失败']);
            }
        }
    }
    
    /**
     * 更新起航旗
     * @return bool|\think\response\Json
     * dt_id     轮次ID
     * dt_flag_start_id    起航旗ID
     */
    public function setStartFalg(){
        $dt_id = input('dt_id'); // 轮次ID
        $dt_flag_start_id = input('dt_flag_start_id'); // 起航旗ID
        $turns = json_decode($this->redis->get('turns_' . $dt_id), true);
        if($turns['dt_flag_start_id'] == $dt_flag_start_id){
            return json(['status' => 200, 'msg' => $turns]);
        }else{
            $res = Db::table('up_sailboat_drill_turns')->where('dt_id', $dt_id)->setField('dt_flag_start_id', $dt_flag_start_id);
            if($res){
                $turns['dt_flag_start_id'] = $dt_flag_start_id;
                $this->redis->set('turns_' . $dt_id, json_encode($turns));
                return json(['status' => 200, 'msg' => $this->pageDisplay($dt_id)]);
            }else{
                return json(['status' => 0, 'msg' => '编辑失败']);
            }
        }
    }
    
    /**
     * 更新轮次
     * @return bool|\think\response\Json
     * dt_id     轮次ID
     * dt_turns    轮次
     */
    public function setTurns(){
        $dt_id = input('dt_id'); // 轮次ID
        $dt_turns = input('dt_turns'); // 轮次
        $turns = json_decode($this->redis->get('turns_' . $dt_id), true);
        if($turns['dt_turns'] == $dt_turns){
            return json(['status' => 200, 'msg' => $turns]);
        }else{
            $exist = Db::table('up_sailboat_drill_turns')
                ->where(['dt_turns' => $dt_turns, 'dt_id' => $dt_id])
                ->find();
            if($exist) return json(['status' => 0, 'msg' => '该轮次已经选择过']);
                
            $res = Db::table('up_sailboat_drill_turns')->where('dt_id', $dt_id)->setField('dt_turns', $dt_turns);
            if($res){
                $turns['dt_turns'] = $dt_turns;
                $this->redis->set('turns_' . $dt_id, json_encode($turns));
                return json(['status' => 200, 'msg' => $this->pageDisplay($dt_id)]);
            }else{
                return json(['status' => 0, 'msg' => '编辑失败']);
            }
        }
    }
    
    /**
     * 更新信号旗
     * @return bool|\think\response\Json
     * dt_id     轮次ID
     * dt_flag_signal_id    信号旗ID
     */
    public function setSignalFlag(){
        $dt_id = input('dt_id'); // 轮次ID
        $dt_flag_signal_id = input('dt_flag_signal_id'); // 信号旗ID
        $turns = json_decode($this->redis->get('turns_' . $dt_id), true);
        if($turns['dt_flag_signal_id'] == $dt_flag_signal_id){
            return json(['status' => 200, 'msg' => $turns]);
        }else{
            $res = Db::table('up_sailboat_drill_turns')->where('dt_id', $dt_id)->setField('dt_flag_signal_id', $dt_flag_signal_id);
            if($res){
                $turns['dt_flag_signal_id'] = $dt_flag_signal_id;
                $this->redis->set('turns_' . $dt_id, json_encode($turns));
                return json(['status' => 200, 'msg' => $this->pageDisplay($dt_id)]);
            }else{
                return json(['status' => 0, 'msg' => '编辑失败']);
            }
        }
    }
    
    /**
     * 更新电子围栏
     * @return bool|\think\response\Json
     * dt_id     轮次ID
     * dt_e_fence    电子围栏
     */
    public function setFence(){
        $dt_id = input('dt_id'); // 轮次ID
        $dt_e_fence = input('dt_e_fence'); // 电子围栏
        $turns = json_decode($this->redis->get('turns_' . $dt_id), true);
        if($turns['dt_e_fence'] == $dt_e_fence){
            return json(['status' => 200, 'msg' => $turns]);
        }else{
            $res = Db::table('up_sailboat_drill_turns')->where('dt_id', $dt_id)->setField('dt_e_fence', $dt_e_fence);
            if($res){
                $turns['dt_e_fence'] = $dt_e_fence;
                $this->redis->set('turns_' . $dt_id, json_encode($turns));
                return json(['status' => 200, 'msg' => $this->pageDisplay($dt_id)]);
            }else{
                return json(['status' => 0, 'msg' => '编辑失败']);
            }
        }
    }
    
    /**
     * 更新航线图
     * @return \think\response\Json
     * dt_id      轮次ID
     * dt_msi_id      航线图ID
     */
    public function setMsi(){
        $dt_id = input('dt_id');
        $dt_msi_id = input('dt_msi_id'); // 航线图ID
        $turns = json_decode($this->redis->get('turns_' . $dt_id), true);
        if($turns['dt_msi_id'] == $dt_msi_id){
            return json(['status' => 200, 'msg' => $turns]);
        }else{
            $sail_image = Db::table('up_match_sail_image')
                ->field('msi_raobiao, msi_biao_name')->where('msi_id', $dt_msi_id)->find();
            
            // 绑定轮次标，如果已经存在，就删除
            $is_insert = Db::table('up_sailboat_drill_match_sensor_device')->where(['dms_dt_id' => $dt_id, 'dms_type' => ['<>', 5]])->find();
            if($is_insert){
                Db::table('up_sailboat_drill_match_sensor_device')->where(['dms_dt_id' => $dt_id, 'dms_type' => ['<>', 5]])->delete();
            }
            $point_arr = explode('-', $sail_image['msi_biao_name']); // 存放所有标
            $point_one = []; // 存放标名-区别于绕标顺序
            Db::startTrans();
            try{
                foreach($point_arr as $k => $v){
                    if(strpos($v, '/') !== false){ // 双点标
                        $double_point = explode('/', $v);
                        if($double_point[0] == 'SL' || $double_point[0] == 'SR'){
                            $dms_type = 2;
                        }elseif($double_point[0] == 'FR' || $double_point[0] == 'FL'){
                            $dms_type = 3;
                        }else{
                            $dms_type = 4;
                        }
                        Db::table('up_sailboat_drill_match_sensor_device')
                            ->insertAll([
                                ['dms_name' => $double_point[0], 'dms_dm_id' => $turns['dt_dm_id'], 'dms_dt_id' => $dt_id, 'dms_type' => $dms_type],
                                ['dms_name' => $double_point[1], 'dms_dm_id' => $turns['dt_dm_id'], 'dms_dt_id' => $dt_id, 'dms_type' => $dms_type]
                            ]);
                        array_push($point_one, $double_point[0], $double_point[1]);
                    }else{
                        Db::table('up_sailboat_drill_match_sensor_device')
                            ->insert([
                                'dms_name' => $v,
                                'dms_dm_id' => $turns['dt_dm_id'],
                                'dms_dt_id' => $dt_id,
                                'dms_type' => 4
                            ]);
                        array_push($point_one, $v);
                    }
                }
    
                // 组装绕标顺序，插入运动员详情表
                $raobiao_order = explode('-', $sail_image['msi_raobiao']);
                $biao_order = []; // 存放绕标顺序
                foreach($raobiao_order as $k => $v){
                    $points = explode('@', $v);
                    array_push($biao_order, $points[0]);
                }
                $biao_str = implode('-', $biao_order);
                Db::table('up_sailboat_drill_match_user_detail')
                    ->where('dmd_dt_id', $dt_id)
                    ->update([
                        'dmd_biao' => $biao_str,
                        'dmd_next_biao1' => 'SL',
                        'dmd_next_biao2' => 'SR',
                        'dmd_next_distance' => 0,
                        'dmd_to_first_distance' => 0,
                        'dmd_to_prior_distance' => 0
                    ]);
    
                // 更新轮次信息
                $point_one_str = implode('-', $point_one);
                Db::table('up_sailboat_drill_turns')->where('dt_id', $dt_id)
                    ->update(['dt_msi_id' => $dt_msi_id, 'dt_biao_name' => $point_one_str]);
                
                Db::commit();
                $turns['dt_msi_id'] = $dt_msi_id;
                $turns['dt_biao_name'] = $point_one;
                $this->redis->set('turns_' . $dt_id, json_encode($turns));
                return json(['status' => 200, 'msg' => $this->pageDisplay($dt_id), 'biao' => $point_one]);
            }catch(\Exception $e){
                return json(['status' => 0, 'msg' => $e->getMessage()]);
            }
        }
    }
    
    /**
     * 可以选择的轮次数组
     * @return \think\response\Json
     * dt_dm_id     训练赛ID
     */
    public function canChooseTurns(){
        $dt_dm_id = input('dt_dm_id');
        $all = range(1, 12);
        $already_choose = Db::table('up_sailboat_drill_turns')
            ->where(['dt_dm_id' => $dt_dm_id, 'dt_status' => 3])
            ->column('dt_turns');
        $can_choose = array_diff($all, $already_choose);
        return json(['status' => 200, 'msg' => array_values($can_choose)]);
    }
    
    /**
     * 绑定标
     * @return \think\response\Json
     * dt_id      轮次ID
     * biao_name     标名
     * sensor_code    被绑定的设备编号
     */
    public function bindingSensor(){
        $dt_id = input('dt_id');
        $biao_name = input('biao_name');
        $sensor_code = input('sensor_code');
        
        // 设备是否存在
        $is_have = Db::table('up__sensor')->where('app_number', $sensor_code)->find();
        if(!$is_have) return json(['status' => 0, 'msg' => '设备编号不存在']);
        
        // 查找该设备是否已被绑定
        $is_binding = Db::table('up_sailboat_drill_match_sensor_device')
            ->where(['dms_sensor_id' => $sensor_code, 'dms_dt_id' => $dt_id])
            ->field('dms_name')
            ->find();
        $repet_biao = ['SR', 'SL', 'FR', 'FL']; // 可重复绑定的标
        if($is_binding){
            if(!in_array($is_binding['dms_name'], $repet_biao)){
                return json(['status' => 0, 'msg' => '该设备已绑定到其它浮标']);
            }
            if(($biao_name == 'SR' && $is_binding['dms_name'] == 'SL') || ($biao_name == 'SL' && $is_binding['dms_name'] == 'SR') || ($biao_name == 'FR' && $is_binding['dms_name'] == 'FL') || ($biao_name == 'FL' && $is_binding['dms_name'] == 'FR')){
                return json(['status' => 0, 'msg' => '起始线或终点线门标不可相同']);
            }
        }
        
        Db::startTrans();
        try{
            // 绑定到轮次设备绑定表
            Db::table('up_sailboat_drill_match_sensor_device')
                ->where(['dms_dt_id' => $dt_id, 'dms_name' => $biao_name, 'dms_type' => ['<>', 5]])
                ->update(['dms_sensor_id' => $sensor_code]);
            
            // 绑定到训练赛用户详情表
            if($biao_name == 'SL' || $biao_name == 'SR'){
                if($biao_name == 'SL') $filed = 'dmd_next_biao1_sid';
                if($biao_name == 'SR') $filed = 'dmd_next_biao2_sid';
                Db::table('up_sailboat_drill_match_user_detail')->where('dmd_dt_id', $dt_id)->update([$filed => $sensor_code]);
            }
            
            Db::commit();
            return json(['status' => 200, 'msg' => '绑定成功']);
        }catch(\Exception $e){
            Db::rollback();
            return json(['status' => 0, 'msg' => $e->getMessage()]);
        }
    }
    
    /**
     * 解绑标
     * @return \think\response\Json
     * dt_id    轮次ID
     * biao_name    标名
     */
    public function cancelSensor(){
        $dt_id = input('dt_id');
        $biao_name = input('biao_name');
        $res = Db::table('up_sailboat_drill_match_sensor_device')
            ->where(['dms_dt_id' => $dt_id, 'dms_name' => $biao_name, 'dms_type' => ['<>', 5]])
            ->setField('dms_sensor_id', null);
        if($res){
            return json(['status' => 200, 'msg' => '解绑成功']);
        }else{
            return json(['status' => 0, 'msg' => '解绑失败']);
        }
    }
    
    /**
     * 裁判员页面信息展示
     * @return \think\response\Json
     * dt_id    轮次ID
     */
    public function matchView(){
        $dt_id = input('dt_id');
        $turns = $this->pageDisplay($dt_id);
        return json(['status' => 200, 'msg' => $turns]);
    }
    
    /**
     * 开始某个轮次的比赛
     * @return \think\response\Json
     * dt_id      轮次ID
     */
    public function beginDrillMatch(){
        $dt_id = input('dt_id');
        $match = Db::table('up_sailboat_drill_turns')
            ->join('up_sailboat_drill_match', 'dm_id = dt_dm_id', 'LEFT')
            ->where('dt_id', $dt_id)
            ->field('dm_create_user_id, dm_id')
            ->find();
        if(!$this->user_id || $this->user_id != $match['dm_create_user_id']) return json(['status' => 0, 'msg' => '教练员身份信息错误']);
        
        $turns = json_decode($this->redis->get('turns_' . $dt_id), true);
//        print_r($turns);die;
        if(!$turns['dt_turns'] || !$turns['dt_count_down'] || !$turns['dt_msi_id'] || !$turns['dt_flag_start_id']){
            return json(['status' => 0, 'msg' => '请先完善训练信息']);
        }
        
        // 所有小船
        $boat_arr = Db::table('up_sailboat_drill_match_sensor_device')
            ->where(['dms_dt_id' => $dt_id, 'dms_type' => 5])
            ->field('dms_name, dms_sensor_id')
            ->select();
        $this->redis->set('boat_arr_' . $dt_id, json_encode($boat_arr));
        // 初始化所有小船坐标
        foreach($boat_arr as $ke => $vo){
            $this->redis->rm($vo['dms_sensor_id']);
        }
        // 所有浮标
        $sensor_arr = Db::table('up_sailboat_drill_match_sensor_device')
            ->where(['dms_dt_id' => $dt_id, 'dms_type' => ['<>', 5]])
            ->column('dms_name, dms_sensor_id');
//            ->field('dms_name, dms_sensor_id')
//            ->select();
        $this->redis->set('sensor_arr_' . $dt_id, json_encode($sensor_arr));
        
        
        $time = microtime(true);
        $now = time();
        //开始训练赛
        Db::startTrans();
        try{
            // 开始训练赛轮次
            Db::table("up_sailboat_drill_turns")->where('dt_id', $dt_id)->update([
                'dt_start_time' => $time,
                'dt_status'       => 2,
                'dt_start_datetime' => $now
            ]);
            $turns = Db::table('up_sailboat_drill_turns')->where('dt_id', $dt_id)->find();
            $this->redis->set('turns_' . $dt_id, json_encode($turns));
            // 开始训练赛
            Db::table("up_sailboat_drill_match")->where('dm_id', $match['dm_id'])->update([
                'dm_start_time' => $time,
                'dm_status'       => 2,
            ]);
            
            // 更新运动员浮标
            Db::table('up_sailboat_drill_match_user_detail')
                ->where('dmd_dt_id', $dt_id)
                ->update([
                    'dmd_next_biao1_sid' => $sensor_arr['SL'],
                    'dmd_next_biao2_sid' => $sensor_arr['SR']
                ]);
            // 所有参加训练的运动员信息
            $sporter = Db::table('up_sailboat_drill_match_user_detail')
                ->where('dmd_dt_id', $dt_id)
                ->field('dmd_id, dmd_user_id, dmd_status, dmd_biao, dmd_now_biao1, dmd_now_biao1_sid, dmd_now_biao2, 
                dmd_now_biao2_sid, dmd_next_biao1, dmd_next_biao1_sid, dmd_next_biao2, dmd_next_biao2_sid, dmd_line_level, 
                dmd_speed, dmd_isoparmspeed')
                ->select();
            $this->redis->set('sporter_' . $dt_id, json_encode($sporter));
    
            //开启定时数据计算
            (new QueueService())->startDrillMatch($dt_id);
            
            Db::commit();
            return json(array('status' => 200, 'msg' => "训练赛开始", 'start_time' => $time, 'now' => $now));
        }catch(\Exception $e){
            Db::rollback();
            return json(['status' => 0, 'msg' => '训练赛开始失败' . $e->getMessage()]);
        }
    }
    
    /**
     * 训练赛数据计算
     * @param $dt_id   轮次ID
     */
    public function calculateDatas($dt_id){
        $match = Db::table('up_sailboat_drill_turns')
            ->join('up_sailboat_drill_match', 'dm_id = dt_dm_id', 'LEFT')
            ->where('dt_id', $dt_id)
            ->field('dm_start_time')
            ->find();
        $turns = json_decode($this->redis->get('turns_' . $dt_id), true);
        $now = microtime(true);
        $time = time();
        $sensor_arr = json_decode($this->redis->get('sensor_arr_' . $dt_id), true); // 浮标名称和设备编号对应数组
        if($match['dm_start_time'] + $turns['dt_count_down'] > $now){
            // 说明倒计时没结束
            
        }else{
            $sporter = json_decode($this->redis->get('sporter_' . $dt_id), true);
            foreach($sporter as $k => $v){
                //小船的位置
                $boat = json_decode($this->redis->get('drill_' . $v['dmd_user_id']), true);
                if($boat){
                    // boat_location   存放小船的经纬度
                    $boat_location['lon'] = $boat['lon'];
                    $boat_location['lat'] = $boat['lat'];
    
                    // 小船现在和上一秒位置  temp_loaction
                    $temp_loaction = json_decode($this->redis->get('drill_boat_location_' . $v['dmd_user_id']), true);
                    if($temp_loaction){
                        if(count($temp_loaction) == 2){
                            unset($temp_loaction[0]);
                        }
                    }else{
                        $temp_loaction = [];
                    }
                    array_push($temp_loaction, $boat_location);
                    $temp_loaction = array_values($temp_loaction);
                    $this->redis->set('drill_boat_location_' . $v['dmd_user_id'], json_encode($temp_loaction));
    
                    // 小船现在和上一秒距离下一个目标点的距离   parallel
                    $parallel = json_decode($this->redis->get('drill_boat_parallel_' . $v['dmd_user_id']), true);
                    if($parallel){
                        if(count($parallel) == 2){
                            unset($parallel[0]);
                        }
                    }else{
                        $parallel = [];
                    }
    
                    // 设备定位
                    $sensor1 = json_decode($this->redis->get($v['dmd_next_biao1_sid']), true);
                    // sensor_location  存放下一个目标的经纬度，有可能是单标，有可能是双标
                    $sensor_location['lon1'] = $sensor1['lon'];
                    $sensor_location['lat1'] = $sensor1['lat'];
                    if($v['dmd_next_biao2']){
                        $sensor2 = json_decode($this->redis->get($v['dmd_next_biao2_sid']), true);
                        $sensor_location['lon2'] = $sensor2['lon'];
                        $sensor_location['lat2'] = $sensor2['lat'];
                    }else{
                        $sensor_location['lon2'] = '';
                        $sensor_location['lat2'] = '';
                    }
    
                    // 速度
                    if(count($temp_loaction) != 2){
                        $dmd_speed = 0;
                    }else{
                        $dmd_speed = $this->getSpeed($temp_loaction[1], $temp_loaction[0]);
                    }
    
                    //**************************************   循环计算小船的数据  start
                    if($v['dmd_line_level'] == 0){
                        $is_across = $this->acrossLine($boat_location, $sensor_location);
                        /*
                         * 小船的位置，有没有过起航线，以SL->SR为向量线段，判断小船在线段左边还是右边，
                         * 左边则表示过起航线了，右侧说明没过起航线
                        */
                        if($is_across == 1 || $is_across == 2){ // 1 左侧  2 起航线上，过起航线
                            // todo：更新小船状态、更新当前设备和目标设备、绕标等级+1、更新距离下一个点的距离
            
                            // 更新浮标设备
                            $new_point = [
                                'dmd_now_biao1' => $v['dmd_next_biao1'],
                                'dmd_now_biao1_sid' => $v['dmd_next_biao1_sid'],
                                'dmd_now_biao2' => $v['dmd_next_biao2'],
                                'dmd_now_biao2_sid' => $v['dmd_next_biao2_sid'],
                                'dmd_line_level' => $v['dmd_line_level'] + 1,
                                'dmd_status' => 2
                            ];
                            $biao_arr = explode('-', $v['dmd_biao']);
                            $next_point = $biao_arr[1]; // 下一个标
                            unset($biao_arr[0]);
                            $new_point['dmd_biao'] = implode('-', $biao_arr);
                            if(strpos($next_point, '/') !== false){ // 双标
                                $a = explode('/', $next_point);
                                $new_point['dmd_next_biao1'] = $a[0];
                                $new_point['dmd_next_biao1_sid'] = $sensor_arr[$a[0]];
                                $new_point['dmd_next_biao2'] = $a[1];
                                $new_point['dmd_next_biao2_sid'] = $sensor_arr[$a[1]];
                            }else{
                                $new_point['dmd_next_biao1'] = $next_point;
                                $new_point['dmd_next_biao1_sid'] = $sensor_arr[$next_point];
                                $new_point['dmd_next_biao2'] = '';
                                $new_point['dmd_next_biao2_sid'] = '';
                            }
            
                            // 距离下一个标的等位线距离
                            $distance = $this->getLastDistance($new_point, $boat_location);
                            $new_point['dmd_next_distance'] = $distance;
                            // 速度
                            $new_point['dmd_speed'] = $dmd_speed;
                            // 水平速度
                            $new_point['dmd_isoparmspeed'] = 0;
                            // 距离终点标距离
                            $finish_distance = $this->getFinishDistance($boat_location, $sensor_arr, $new_point['dmd_biao']);
                            $new_point['dmd_to_finish_distance'] = $finish_distance;
            
                            // 用于计算速度
                            $parallel_cell = ['distance' => $distance, 'level' => $new_point['dmd_line_level']];
                            array_push($parallel, $parallel_cell);
                            $parallel = array_values($parallel);
                            $this->redis->set('drill_boat_parallel_' . $v['dmd_user_id'], json_encode($parallel));
            
                            // *******************************    起航数据 start
                            $SL = json_decode($this->redis->get($sensor_arr['SL']), true);
                            $SR = json_decode($this->redis->get($sensor_arr['SR']), true);
            
                            /******** 过起航线角度&&船只到达起始线位置 ********/
                            if(count($temp_loaction) != 2){
                                $dmd_to_start_angle = 0;
                                $start_line_location = 0;
                            }else{
                                $on_line = $this->judgeInLine($SL, $SR, $temp_loaction[1], $temp_loaction[0], 1);
                                // 是否与起航线相交
                                if($on_line){
                                    $dmd_to_start_angle = $this->getAngle($temp_loaction[1], $temp_loaction[0], $SL, $SR);
                                    $start_line_location = $this->getLocation($SL, $SR);
                                }else{
                                    $dmd_to_start_angle = 0;
                                    $start_line_location = 0;
                                }
                            }
                            $new_point['to_start_angle'] = $dmd_to_start_angle;
                            $new_point['start_line_location'] = $start_line_location;
            
                            /******** 船只到达起始线时间与倒计时0差值 **********/
                            $to_start_time = $now - ($turns['dt_count_down'] + $turns['dt_start_time']);
                            $new_point['start_line_time'] = number_format((float)$to_start_time, 2);
            
                            /******** 小船到达起航线的速度 ********/
                            $new_point['start_line_speed'] = $dmd_speed;
            
                            // ********************************     起航数据  end
            
                            $sporter[$k]['dmd_status'] = $new_point['dmd_status'];
                            $sporter[$k]['dmd_biao'] = $new_point['dmd_biao'];
                            $sporter[$k]['dmd_now_biao1'] = $new_point['dmd_now_biao1'];
                            $sporter[$k]['dmd_now_biao1_sid'] = $new_point['dmd_now_biao1_sid'];
                            $sporter[$k]['dmd_now_biao2'] = $new_point['dmd_now_biao2'];
                            $sporter[$k]['dmd_now_biao2_sid'] = $new_point['dmd_now_biao2_sid'];
                            $sporter[$k]['dmd_next_biao1'] = $new_point['dmd_next_biao1'];
                            $sporter[$k]['dmd_next_biao1_sid'] = $new_point['dmd_next_biao1_sid'];
                            $sporter[$k]['dmd_next_biao2'] = $new_point['dmd_next_biao2'];
                            $sporter[$k]['dmd_next_biao2_sid'] = $new_point['dmd_next_biao2_sid'];
                            $sporter[$k]['dmd_line_level'] = $new_point['dmd_line_level'];
                            $sporter[$k]['dmd_speed'] = $new_point['dmd_speed'];
                            $sporter[$k]['dmd_isoparmspeed'] = $new_point['dmd_isoparmspeed'];
                        }else{
                            $new_point = [
                                'dmd_next_distance' => 0,
                                'to_start_angle' => 0,
                                'dmd_to_first_distance' => 0,
                                'dmd_to_prior_distance' => 0,
                                'dmd_to_finish_distance' => $this->getFinishDistance($boat_location, $sensor_arr, $v['dmd_biao']),
                                'dmd_speed' => 0,
                                'dmd_isoparmspeed' => 0,
                                'start_line_time' => 0,
                                'start_line_location' => 0,
                                'start_line_speed' => 0,
                            ];
                        }
                        // 更新表和redis数据
                        Db::table('up_sailboat_drill_match_user_detail')->where('dmd_id', $v['dmd_id'])->update($new_point);
                    }else{
                        if($v['dmd_status'] == 2){
                            if($v['dmd_next_biao1'] == 'FR' || $v['dmd_next_biao1'] == 'FL'){
                                // 判断下个标是不是终点标
                                $is_across = $this->acrossLine($boat_location, $sensor_location);
                                if($is_across == 1 || $is_across == 2){ // 过终点标
                                    // 更新浮标设备
                                    $new_point = [
                                        'dmd_now_biao1' => $v['dmd_next_biao1'],
                                        'dmd_now_biao1_sid' => $v['dmd_next_biao1_sid'],
                                        'dmd_now_biao2' => $v['dmd_next_biao2'],
                                        'dmd_now_biao2_sid' => $v['dmd_next_biao2_sid'],
                                        'dmd_line_level' => $v['dmd_line_level'] + 1,
                                        'dmd_status' => 3,
                                        'dmd_biao' => '',
                                        'dmd_next_biao1' => '',
                                        'dmd_next_biao1_sid' => '',
                                        'dmd_next_biao2' => '',
                                        'dmd_next_biao2_sid' => '',
//                                    'dmd_next_distance' => 0,
                                        'dmd_finish_time' => $time
                                    ];
                                    $distance = 0;
                                    $dmd_to_finish_distance = 0;
                                }else{
                                    $new_point = [
                                        'dmd_now_biao1' => $v['dmd_now_biao1'],
                                        'dmd_now_biao1_sid' => $v['dmd_now_biao1_sid'],
                                        'dmd_now_biao2' => $v['dmd_now_biao2'],
                                        'dmd_now_biao2_sid' => $v['dmd_now_biao2_sid'],
                                        'dmd_line_level' => $v['dmd_line_level'],
                                        'dmd_status' => 2,
                                        'dmd_next_biao1' => $v['dmd_next_biao1'],
                                        'dmd_next_biao1_sid' => $v['dmd_next_biao1_sid'],
                                        'dmd_next_biao2' => $v['dmd_next_biao2'],
                                        'dmd_next_biao2_sid' => $v['dmd_next_biao2_sid'],
                                        'dmd_biao' => $v['dmd_biao']
                                    ];
                                    // 距离下一个标的等位线距离
                                    $distance = $this->getLastDistance($new_point, $boat_location);
                                    // 到终点距离
                                    $dmd_to_finish_distance = $this->getFinishDistance($boat_location, $sensor_arr, $v['dmd_biao']);
                                }
                
                                $new_point['dmd_next_distance'] = $distance;
                                $new_point['dmd_to_finish_distance'] = $dmd_to_finish_distance;
                                
                                // 用于计算水平速度
                                $parallel_cell = ['distance' => $distance, 'level' => $new_point['dmd_line_level']];
                            }else{
                                $is_across = $this->isAcross($boat_location, $sensor_location);
                                if($is_across == 1){ // 绕标成功
                                    // 更新浮标设备
                                    $new_point = [
                                        'dmd_now_biao1' => $v['dmd_next_biao1'],
                                        'dmd_now_biao1_sid' => $v['dmd_next_biao1_sid'],
                                        'dmd_now_biao2' => $v['dmd_next_biao2'],
                                        'dmd_now_biao2_sid' => $v['dmd_next_biao2_sid'],
                                        'dmd_line_level' => $v['dmd_line_level'] + 1,
                                        'dmd_status' => 2
                                    ];
                                    $biao_arr = explode('-', $v['dmd_biao']);
                                    $biao_arr = array_filter($biao_arr);
                                    if(count($biao_arr) == 1){ // 最后一个标
                                        $new_point['dmd_next_biao1'] = 'FL';
                                        $new_point['dmd_next_biao1_sid'] = $sensor_arr['FL'];
                                        $new_point['dmd_next_biao2'] = 'FR';
                                        $new_point['dmd_next_biao2_sid'] = $sensor_arr['FR'];
                                        $new_point['dmd_biao'] = '';
                                    }else{
                                        $next_point = $biao_arr[1]; // 下一个标
                                        unset($biao_arr[0]);
                                        $new_point['dmd_biao'] = implode('-', $biao_arr);
                                        if(strpos($next_point, '/') !== false){ // 双标
                                            $a = explode('/', $next_point);
                                            $new_point['dmd_next_biao1'] = $a[1];
                                            $new_point['dmd_next_biao1_sid'] = $sensor_arr[$a[1]];
                                            $new_point['dmd_next_biao2'] = $a[0];
                                            $new_point['dmd_next_biao2_sid'] = $sensor_arr[$a[0]];
                                        }else{
                                            $new_point['dmd_next_biao1'] = $next_point;
                                            $new_point['dmd_next_biao1_sid'] = $sensor_arr[$next_point];
                                            $new_point['dmd_next_biao2'] = '';
                                            $new_point['dmd_next_biao2_sid'] = '';
                                        }
                                    }
                                }else{
                                    $new_point = [
                                        'dmd_now_biao1' => $v['dmd_now_biao1'],
                                        'dmd_now_biao1_sid' => $v['dmd_now_biao1_sid'],
                                        'dmd_now_biao2' => $v['dmd_now_biao2'],
                                        'dmd_now_biao2_sid' => $v['dmd_now_biao2_sid'],
                                        'dmd_line_level' => $v['dmd_line_level'],
                                        'dmd_status' => 2,
                                        'dmd_next_biao1' => $v['dmd_next_biao1'],
                                        'dmd_next_biao1_sid' => $v['dmd_next_biao1_sid'],
                                        'dmd_next_biao2' => $v['dmd_next_biao2'],
                                        'dmd_next_biao2_sid' => $v['dmd_next_biao2_sid'],
                                        'dmd_biao' => $v['dmd_biao']
                                    ];
                                }
                                // 距离下一个标的等位线距离
                                $distance = $this->getLastDistance($new_point, $boat_location);
                                $new_point['dmd_next_distance'] = $distance;
                                // 到终点距离
                                $dmd_to_finish_distance = $this->getFinishDistance($boat_location, $sensor_arr, $new_point['dmd_biao']);
                                $new_point['dmd_to_finish_distance'] = $dmd_to_finish_distance;
                
                                // 用于计算水平速度
                                $parallel_cell = ['distance' => $distance, 'level' => $new_point['dmd_line_level']];
                            }
                            // 速度
                            $new_point['dmd_speed'] = $dmd_speed;
            
                            // 水平速度
                            array_push($parallel, $parallel_cell);
                            $parallel = array_values($parallel);
                            $this->redis->set('drill_boat_parallel_' . $v['dmd_user_id'], json_encode($parallel));
                            if(count($parallel) == 2){
//                                $isoparmspeed = 1.94386 * abs($parallel[0]['distance'] - $parallel[1]['distance']);
//                                $new_point['dmd_isoparmspeed'] = number_format($isoparmspeed, 2);
//                                // 如果绕标等级相同，则计算水平距离，如果不同，则不计算
                                if($parallel[0]['level'] == $parallel[1]['level']){
                                    $isoparmspeed = 1.94386 * abs($parallel[0]['distance'] - $parallel[1]['distance']);
                                    $new_point['dmd_isoparmspeed'] = number_format($isoparmspeed, 2);
                                }else{
//                                $new_point['dmd_isoparmspeed'] = $v['dmd_isoparmspeed'];
                                    $new_point['dmd_isoparmspeed'] = 0;
                                }
                            }else{
                                $new_point['dmd_isoparmspeed'] = 0;
                            }
            
                            // 更新表和redis数据
                            Db::table('up_sailboat_drill_match_user_detail')->where('dmd_id', $v['dmd_id'])->update($new_point);
            
                            $sporter[$k]['dmd_status'] = $new_point['dmd_status'];
                            $sporter[$k]['dmd_biao'] = $new_point['dmd_biao'];
                            $sporter[$k]['dmd_now_biao1'] = $new_point['dmd_now_biao1'];
                            $sporter[$k]['dmd_now_biao1_sid'] = $new_point['dmd_now_biao1_sid'];
                            $sporter[$k]['dmd_now_biao2'] = $new_point['dmd_now_biao2'];
                            $sporter[$k]['dmd_now_biao2_sid'] = $new_point['dmd_now_biao2_sid'];
                            $sporter[$k]['dmd_next_biao1'] = $new_point['dmd_next_biao1'];
                            $sporter[$k]['dmd_next_biao1_sid'] = $new_point['dmd_next_biao1_sid'];
                            $sporter[$k]['dmd_next_biao2'] = $new_point['dmd_next_biao2'];
                            $sporter[$k]['dmd_next_biao2_sid'] = $new_point['dmd_next_biao2_sid'];
                            $sporter[$k]['dmd_line_level'] = $new_point['dmd_line_level'];
                            $sporter[$k]['dmd_speed'] = $new_point['dmd_speed'];
                            $sporter[$k]['dmd_isoparmspeed'] = $new_point['dmd_isoparmspeed'];
                        }
                    }
                }
            }
            $this->redis->set('sporter_' . $dt_id, json_encode($sporter));
            
            // 循环更新成绩
            $boat_info = Db::table('up_sailboat_drill_match_user_detail')
                ->where('dmd_dt_id', $dt_id)
                ->field('dmd_id, dmd_status, dmd_user_id')
                ->order('dmd_line_level desc, dmd_next_distance asc, dmd_finish_time asc')
                ->select();
            foreach($boat_info as $kk => $vv){
                // 名次
                $update['dmd_ranking'] = $kk + 1;
                // 距离前一名距离
                $update['dmd_to_prior_distance'] = 0;
                // 距离第一名距离
                $update['dmd_to_first_distance'] = 0;
                if($vv['dmd_status'] == 2){ // 进行中
                    if($kk != 0){
                        // 前一名
                        $front = json_decode($this->redis->get('drill_' . $boat_info[$kk - 1]['dmd_user_id']), true);
                        $front_point = ['lon' => $front['lon'], 'lat' => $front['lat']];
                        // 第一名
                        $first = json_decode($this->redis->get('drill_' . $boat_info[0]['dmd_user_id']), true);
                        $first_point = ['lon' => $first['lon'], 'lat' => $first['lat']];
                        // 我的
                        $my = json_decode($this->redis->get('drill_' . $vv['dmd_user_id']), true);
                        $my_point = ['lon' => $my['lon'], 'lat' => $my['lat']];
                        $update['dmd_to_prior_distance'] = $this->getDistance($my_point, $front_point);
                        $update['dmd_to_first_distance'] = $this->getDistance($my_point, $first_point);
                    }
                }
                Db::table('up_sailboat_drill_match_user_detail')->where('dmd_id', $vv['dmd_id'])->update($update);
            }
            
            $step_data = [];
            $boat_arr = json_decode($this->redis->get('boat_arr_' . $dt_id), true);
            if(is_array($boat_arr) && $boat_arr){
                foreach($boat_arr as $kkk => $vvv){
                    $_dms_sensor_id = json_decode($this->redis->get($vvv['dms_sensor_id']), true);
                    if($_dms_sensor_id){
                        $step_data[$vvv['dms_sensor_id']] = $_dms_sensor_id;
                    }
                }
            }
            foreach($sensor_arr as $ke => $vo){
                $step_data[$vo] = json_decode($this->redis->get($vo), true);
            }
            Db::table('up_sailboat_drill_match_step')->insert([
                'dms_dt_id' => $dt_id,
                'time'            => $time,
                'data'            => json_encode($step_data)
            ]);
            
            $result = Db::table('up_sailboat_drill_match_user_detail')
                ->join('up_u_user', 'dmd_user_id = user_id', 'LEFT')
                ->where('dmd_dt_id', $dt_id)
                ->field('dmd_sensor_id as device_id, user_id, user_username, dmd_dt_id, dmd_status, dmd_next_biao1_sid, 
                dmd_next_biao1, dmd_next_biao2, dmd_next_biao2_sid, dmd_next_distance, dmd_ranking, to_start_angle,
                dmd_to_first_distance, dmd_to_prior_distance, dmd_finish_time, dmd_now_biao1, dmd_now_biao1_sid, dmd_now_biao2, 
                dmd_now_biao2_sid, dmd_speed, dmd_isoparmspeed, user_club_id, start_line_time, start_line_location, start_line_speed, dmd_to_finish_distance')
                ->order('dmd_ranking asc')
                ->select();
            foreach($result as $key => $val){
                $result[$key]['club_image'] = Db::table('up_club')->where('club_id', $val['user_club_id'])->value('club_image');
            }
            //生成数据快照
            Db::table('up_sailboat_drill_match_datas')->insert([
                'data_dt_id' => $dt_id,
                'time'            => $time,
                'data'            => json_encode($result)
            ]);
            $this->redis->set('up_sailboat_drill_match_datas_' . $dt_id, json_encode($result));
        }
    }
    
    /**
     * 实时获取训练数据
     * @return \think\response\Json
     * dt_id      轮次ID
     */
    public function getLiveDatas(){
        $dt_id = input('dt_id');
        $time = time();
        
        // 轮次配置信息
        $turns = Db::table('up_sailboat_drill_turns')->where('dt_id', $dt_id)->find();
//        $turns = json_decode($this->redis->get('turns_' . $dt_id), true);
        
        // 小船计算结果
        if ($turns['dt_status'] != 1) {
            $boat_calculate_data = json_decode($this->redis->get('up_sailboat_drill_match_datas_' . $dt_id), true);
        } else {
            $boat_calculate_data = Cache::get('boat_calculate_data_' . $dt_id);
            //dump($boat_calculate_data);die;
            if (!$boat_calculate_data) {
                $boat_calculate_data = Db::table('up_sailboat_drill_match_user_detail')
                    ->join('up_u_user', 'dmd_user_id = user_id', 'LEFT')
                    ->where('dmd_dt_id', $dt_id)
                    ->field('dmd_sensor_id as device_id, user_id, user_username, dmd_dt_id, dmd_status, dmd_next_biao1_sid, 
                dmd_next_biao1, dmd_next_biao2, dmd_next_biao2_sid, dmd_next_distance, dmd_ranking, to_start_angle,
                dmd_to_first_distance, dmd_to_prior_distance, dmd_finish_time, dmd_now_biao1, dmd_now_biao1_sid, dmd_now_biao2, 
                dmd_now_biao2_sid, dmd_speed, dmd_isoparmspeed, user_club_id, start_line_time, start_line_location, start_line_speed, dmd_to_finish_distance')
                    ->order('dmd_ranking asc')
                    ->select();
                foreach($boat_calculate_data as $kk => $vv){
                    $boat_calculate_data[$kk]['club_image'] = Db::table('up_club')->where('club_id', $vv['user_club_id'])->value('club_image');
                }
                Cache::set('boat_calculate_data_' . $dt_id, $boat_calculate_data);
            }
        }
        
        // 所有小船和设备坐标
        $location_data = [];
        $all_sensors_id = Cache::get('all_sensors_id_' . $dt_id);
        $sensors_id_arr = Cache::get('sensors_id_arr_' . $dt_id);
    
        if (!$all_sensors_id) {
            $all_sensors_id = Db::table('up_sailboat_drill_match_sensor_device')
                ->where('dms_dt_id', $dt_id)->field('dms_sensor_id, dms_dt_id')->select();
            Cache::set('all_sensors_id', $all_sensors_id);
            $sensors_id_arr = [];
            foreach ($all_sensors_id as $k => $v) {
                array_push($sensors_id_arr, $v['dms_sensor_id']);
            }
            Cache::set('sensors_id_arr_' . $dt_id, $sensors_id_arr);
        }
        foreach ($all_sensors_id as $k => $v) {
            $dms_sensor = $this->redis->get($v['dms_sensor_id']);
            if($dms_sensor){
                $location_data[$v['dms_sensor_id']] = $dms_sensor;
            }
        }
        
        $data = [
            'match_detail_id' => $dt_id,
            'time' => $time,
            'calculate_data' => $boat_calculate_data,
            'locations_data' => $location_data,
            'match_turns_data' => $turns
        ];
        return json(['status' => 200, 'msg' => $data]);
    }
    
    /**
     * 获取比赛回访数据
     * @param $dt_id
     * @param $start
     * @param $scope
     * @return
     */
    public function getPlayBackDatas()
    {
        $dt_id = input('dt_id');
        $start           = input('start');
        $scope           = input('scope');
        if (empty($dt_id) || empty($start) || empty($scope)) {
            return json(array('status' => 100, 'msg' => '参数不能为空'));
        }
        $step_data      = Db::table('up_sailboat_drill_match_step')
            ->where(['dms_dt_id' => $dt_id])
            ->where('time', '>=', $start)
            ->where('time', '<', ($start + $scope))
            ->field('time, data')
            ->select();
        $datas          = Db::table('up_sailboat_drill_match_datas')
            ->where(['data_dt_id' => $dt_id])
            ->where('time', '>=', $start)
            ->where('time', '<', ($start + $scope))
            ->field('time, data')
            ->select();
        $all_data       = [];
        $temp_datas     = [];
        $temp_step_data = [];
        foreach ($datas as $k => $v) {
            array_push($all_data, [
                'time'           => $v['time'],
                'calculate_data' => json_decode($v['data'], true),
                'locations_data' => json_decode($step_data[$k]['data'], true)
            ]);
        }
        
        foreach ($step_data as $k => $v) {
            $temp_step_data[$k][$v['time']] = json_decode($v['data'], true);
        }
        return json(array('status' => 200, 'msg' => 'success', 'data' => $all_data));
    }
    
    /**
     * 结束某个轮次的比赛
     * @return \think\response\Json
     * dt_id     轮次ID
     */
    public function endTurns(){
        $dt_id = input('dt_id');
        // 上一轮信息
        $turns_info = Db::table('up_sailboat_drill_turns')
            ->where('dt_id', $dt_id)
            ->field('dt_dm_id, dt_drill_id, dt_count_down, dt_msi_id, dt_flag_start_id, dt_flag_signal_id, 
            dt_e_fence, dt_biao_name')
            ->find();
        $turns_info['dt_turns'] = 0;
        
        // 用户信息
        $turns_user = Db::table('up_sailboat_drill_match_user_detail')
            ->where('dmd_dt_id', $dt_id)
            ->field('dmd_dm_id, dmd_user_id, dmd_sensor_id')
            ->select();
        $sail_image = Db::table('up_match_sail_image')
            ->field('msi_raobiao, msi_biao_name')->where('msi_id', $turns_info['dt_msi_id'])->find();
        $raobiao_order = explode('-', $sail_image['msi_raobiao']);
        $biao_order = []; // 存放绕标顺序
        foreach($raobiao_order as $k => $v){
            $points = explode('@', $v);
            array_push($biao_order, $points[0]);
        }
        $biao_str = implode('-', $biao_order);
        
        // 浮标和小船信息
        $sensor = Db::table('up_sailboat_drill_match_sensor_device')
            ->where('dms_dt_id', $dt_id)
            ->field('dms_name, dms_sensor_id, dms_dm_id, dms_type')
            ->select();
        
        Db::startTrans();
        try{
            // 修改本轮次的状态
            Db::table('up_sailboat_drill_turns')
                ->where('dt_id', $dt_id)
                ->update(['dt_status' => 3, 'dt_end_time' => microtime(true)]);
            $turns = json_decode($this->redis->get('turns_' . $dt_id), true);
            $turns['dt_end_time'] = microtime(true);
            $this->redis->set('turns_' . $dt_id, json_encode($turns));
            
            // 生成一轮新的轮次
            $new_dt_id = Db::table('up_sailboat_drill_turns')->insertGetId($turns_info);
            
            // 浮标和小船信息
            foreach($sensor as $k => $v){
                $sensor[$k]['dms_dt_id'] = $new_dt_id;
            }
            Db::table('up_sailboat_drill_match_sensor_device')->insertAll($sensor);
            
            // 用户信息
            foreach($turns_user as $k => $v){
                $turns_user[$k]['dmd_dt_id'] = $new_dt_id;
                $turns_user[$k]['dmd_biao'] = $biao_str;
                $turns_user[$k]['dmd_next_biao1'] = 'SL';
                $turns_user[$k]['dmd_next_biao2'] = 'SR';
                $turns_user[$k]['dmd_next_distance'] = 0;
                $turns_user[$k]['dmd_to_first_distance'] = 0;
                $turns_user[$k]['dmd_to_prior_distance'] = 0;
            }
            Db::table('up_sailboat_drill_match_user_detail')->insertAll($turns_user);
            
            Db::commit();
            $new_turns = Db::table('up_sailboat_drill_turns')->where('dt_id', $new_dt_id)->find();
            $this->redis->set('turns_' . $new_dt_id, json_encode($new_turns));
            return json(['status' => 200, 'msg' => $this->pageDisplay($new_dt_id)]);
        }catch(\Exception $e){
            Db::rollback();
            return json(['status' => 0, 'msg' => $e->getMessage()]);
        }
    }
    
    /**
     * 结束训练赛
     * @return \think\response\Json
     * dm_id    训练赛ID
     */
    public function endDrillMatch(){
        $dm_id = input('dm_id'); // 训练赛ID
        // 结束训练赛，并且查找轮次为0的记录，删除该轮的所有其他记录
        $turns = Db::table('up_sailboat_drill_turns')
            ->where(['dt_dm_id' => $dm_id, 'dt_turns' => 0])
            ->field('dt_id')
            ->find();
        
        Db::startTrans();
        try{
            // 修改训练赛状态
            Db::table('up_sailboat_drill_match')
                ->where('dm_id', $dm_id)
                ->update(['dm_status' => 3, 'dm_end_time' => microtime(true)]);
            
            if($turns){
                // 删除未开始的轮次
                Db::table('up_sailboat_drill_turns')->delete($turns['dt_id']);
                // 删除浮标和小船信息
                Db::table('up_sailboat_drill_match_sensor_device')->where('dms_dt_id', $turns['dt_id'])->delete();
                // 删除用户信息
                Db::table('up_sailboat_drill_match_user_detail')->where('dmd_dt_id', $turns['dt_id'])->delete();
            }
            
            Db::commit();
            return json(['status' => 200, 'msg' => '训练赛已结束']);
        }catch(\Exception $e){
            Db::rollback();
            return json(['status' => 0, 'msg' => $e->getMessage()]);
        }
    }
    
    /**
     * 训练赛详情
     * @return \think\response\Json
     * drill_id      训练ID
     */
    public function drillMatchDetail(){
        $drill_id = input('drill_id');
        // 训练
        $drill = Db::table('up_sailboat_drill')
            ->join('up_u_user', 'user_id = drill_create_user_id', 'LEFT')
            ->field('user_id, drill_id, user_username, drill_date, drill_addr')
            ->where('drill_id', $drill_id)
            ->find();
        // 训练赛
        $match = Db::table('up_sailboat_drill_match')
            ->where('dm_drill_id', $drill_id)
            ->field('dm_id, dm_type')
            ->select();
        if($match){
            // 轮次
            foreach($match as $k => $v){
                $turns = Db::table('up_sailboat_drill_turns')
                    ->where(['dt_dm_id' => $v['dm_id'], 'dt_turns' => ['<>', 0]])
                    ->field('dt_id, dt_turns')
                    ->order('dt_turns asc')
                    ->select();
                if($turns){
                    $match[$k]['turns'] = $turns;
                }else{
                    $match[$k]['turns'] = [];
                }
            }
            $drill['match'] = $match;
        }else{
            $drill['match'] = [];
        }
        return json(['status' => 200, 'msg' => $drill]);
    }
    
    /**
     * 计算总成绩和名次
     * @return \think\response\Json
     * dm_id     训练赛ID
     * cutTurns     需要去掉的轮次数量
     */
    public function scoreList(){
        $dm_id = input('dm_id'); // 训练赛ID
        $cutTurns = input('cutTurns'); // 需要去掉的轮次数量
        
        $turns_num = Db::table('up_sailboat_drill_turns')
            ->where('dt_dm_id', $dm_id)
            ->count();
        if($cutTurns > $turns_num) return json(['status' => 0, 'msg' => '去掉的轮次数量超出已训练轮次数量']);
        
        // 训练赛创建者
        $create_user_id = Db::table('up_sailboat_drill_match')
            ->where('dm_id', $dm_id)
            ->value('dm_create_user_id');
        
        $users = Db::table('up_sailboat_drill_match_user')
            ->join('up_u_user', 'user_id = du_user_id', 'LEFT')
            ->field('user_id, user_username, user_image')
            ->where('du_dm_id', $dm_id)
            ->select();
        if($users){
            foreach($users as $k => $v){
                // 获取所有轮次数组，并去掉需要去掉的轮次数
                $detail = Db::table('up_sailboat_drill_match_user_detail')
                    ->join('up_sailboat_drill_turns', 'dt_id = dmd_dt_id', 'LEFT')
                    ->where(['dmd_dm_id' => $dm_id, 'dmd_user_id' => $v['user_id']])
                    ->field('dt_turns, dmd_ranking')
                    ->order('dmd_ranking asc')
                    ->select();
                if($detail){
                    // 去掉需要去掉的轮次数量
                    if($cutTurns != 0){
                        $count = count($detail);
                        $detail = array_slice($detail, 0, $count - $cutTurns);
                    }
                    // 按轮次从小到大排序
                    $turns_arr = array_column($detail,'dt_turns');
                    array_multisort($turns_arr , SORT_ASC, $detail);
                    $turns_ranking = $detail;
//                    $v['turns_ranking'] = $detail;
                }else{
                    $turns_ranking = [];
//                    $v['turns_ranking'] = [];
                }
                $users[$k]['turns_ranking'] = $turns_ranking;
                
                // 算总分
//                if($users[$k]['turns_ranking'] != []){
//                    $totalScore = 0;
//                    foreach($v['turns_ranking'] as $kk => $vv){
//                        $totalScore += $vv['dmd_ranking'];
//                    }
//                }else{
//                    $totalScore = 99999999;
//                }
                if($turns_ranking != []){
                    $totalScore = 0;
                    foreach($turns_ranking as $kk => $vv){
                        $totalScore += $vv['dmd_ranking'];
                    }
                }else{
                    $totalScore = 99999999;
                }
                $users[$k]['total_score'] = $totalScore;
                
            }
            // 按照总分排序
            $score_arr = array_column($users,'total_score');
            array_multisort($score_arr , SORT_ASC, $users);
            
            // 如果总分相同，算小分，小分越多，越靠前
            $number = count($users);
            for($i = 0; $i < $number; $i++){
                for($j = $i + 1; $j < $number; $j++){
                    if($users[$i]['total_score'] == $users[$j]['total_score']){
                        
                        for($t = 1; $t <= $number; $t++){
                            $first = 0; // 前一名小分数量
                            $second = 0; // 后一名小分数量
                            foreach($users[$i]['turns_ranking'] as $kf => $vf){
                                if($vf['dmd_ranking'] == $t) $first++;
                            }
                            foreach($users[$j]['turns_ranking'] as $ks => $vs){
                                if($vs['dmd_ranking'] == $t) $second++;
                            }
                            
                            if($first < $second){ // 如果后一名的小分数量多，则进行交换
                                $tem = $users[$i]; // 这里临时变量，存贮$i的值
                                $users[$i] = $users[$j]; // 第一次更换位置
                                $users[$j] = $tem; // 完成位置互换
                            }
                            
                        }
                        
                    }
                }
            }
    
            // 算名次
            foreach($users as $kr => $vr){
                $users[$kr]['ranking'] = $kr + 1;
            }
            
        }else{
            $users = [];
        }
        return json(['status' => 200, 'msg' => $users, 'create_user_id' => $create_user_id]);
    }
    
    //**********************************************  公共方法
    /**
     * 产生随机数
     * @param $number    设备编号
     * @return mixed
     */
    public function getNumber($number)
    {
//        extract(input());
        $device = Db::table('up__sensor')
            ->where('app_number', $number)
            ->find();
        if ($device) {
            $num = rand(1000, 9999);
            return $this->getNumber($num);
        } else {
            return $number;
        }
    }
    
    /**
     * 生成设备二维码
     * @param $aid       设备编号
     * @return string
     */
    public function createQRcode($aid)
    {
        $dir = $_SERVER['DOCUMENT_ROOT'];
        $url = "http://" . $_SERVER['HTTP_HOST'];
        require_once VENDOR_PATH . "phpqrcode.php";
        $rand                 = date('YmdHis') . rand(100000, 999999);
        $value                = "$aid"; //二维码内容：链接
        $errorCorrectionLevel = 'L';    //容错级别
        $matrixPointSize      = 8;           //生成图片大小
        //生成二维码图片
        $ymd      = date('Ymd');
        $zip_path = "{$dir}/uploads/face/$ymd";
        //dump($zip_path);die;
        if (!file_exists($zip_path)) {
            mkdir($zip_path, 0777, true);
        }
        $filename = "$zip_path/{$rand}.png";
        $filehttp = "{$url}/uploads/face/$ymd/{$rand}.png";
        \QRcode::png($value, $filename, $errorCorrectionLevel, $matrixPointSize, 2);
        $QR = $filename;              //已经生成的原始二维码图片文件
        $QR = imagecreatefromstring(file_get_contents($QR));
        //输出图片
//        imagepng($QR, 'qrcode.png');
        imagedestroy($QR);
        return $filehttp;
    }
    
    /**
     * 裁判员页面内容展示
     * @param $dt_id    轮次ID
     * @return mixed
     */
    public function pageDisplay($dt_id){
        // 配置信息
        $turns = json_decode($this->redis->get('turns_' . $dt_id), true);
        // 航线图
        $msi = Db::table('up_match_sail_image')
            ->where('msi_id', $turns['dt_msi_id'])
            ->field('msi_image, msi_name')
            ->find();
        $turns['msi_image'] = $msi['msi_image'];
        $turns['msi_name'] = $msi['msi_name'];
        // 起航旗
        $setsail = Db::table('up_setsail_flag')
            ->where('sf_id', $turns['dt_flag_start_id'])
            ->field('sf_name, sf_image')
            ->find();
        $turns['sf_name'] = $setsail['sf_name'];
        $turns['sf_image'] = $setsail['sf_image'];
        // 信号旗
        $signal = Db::table('up_flag_signal')
            ->where('fs_id', $turns['dt_flag_signal_id'])
            ->field('fs_name, fs_image')
            ->find();
        $turns['fs_name'] = $signal['fs_name'];
        $turns['fs_image'] = $signal['fs_image'];
        if(!is_array($turns['dt_biao_name'])){
            $turns['dt_biao_name'] = explode('-', $turns['dt_biao_name']);
        }
        
        // 该轮次下所有船和浮标
        $sensor = Db::table('up_sailboat_drill_match_sensor_device')
            ->where('dms_dt_id', $dt_id)
            ->field('dms_name, dms_sensor_id, dms_type, dms_dm_id')
            ->order('dms_type asc')
            ->select();
        if($sensor){
            foreach($sensor as $k => $v){
                $point = json_decode($this->redis->get($v['dms_sensor_id']), true);
                if($point){
                    $sensor[$k]['type'] = $point['type'];
                    $sensor[$k]['lon'] = $point['lon'];
                    $sensor[$k]['lat'] = $point['lat'];
                }else{
                    $sensor[$k]['type'] = '';
                    $sensor[$k]['lon'] = '';
                    $sensor[$k]['lat'] = '';
                }
                if($v['dms_type'] == 5){ // 小船
                    $sensor[$k]['color'] = Db::table('up_sailboat_drill_match_user')->where(['du_dm_id' => $v['dms_dm_id'], 'du_user_id' => $v['dms_name']])->value('du_color');
                }
            }
//            print_r($sensor);die;
            $turns['sensor'] = $sensor;
        }else{
            $turns['sensor'] = [];
        }
        return $turns;
    }
    
    /**
     * 判断小船在浮标线段的哪一侧
     * @param $boat      小船坐标数组
     * @param $sensor    两浮标坐标数组
     * @return int       1 左侧   2 线段上   3 右侧
     */
    public function acrossLine($boat, $sensor){
        /*
            设有向线段AB，两端点A（xa,ya）,B(xb,yb)
            另一点C(xc,yc)
            float f = (xb - xa) * (yc - ya) - (xc - xa) * (yb - ya);
            if(f > 0)
            点C位于有向线段AB的左侧
            else if(f == 0)
            点C位于有向线段AB上（也有可能在延长线上）
            else
            点C位于有向线段AB的右侧
         */
//        $boat = ['lon' => '118.881592', 'lat' => '31.983441'];
//        $sensor = ['lon1' => '118.83169', 'lat1' => '31.949992', 'lon2' => '118.804341', 'lat2' => '31.975024'];
        $start_point = ['lon' => $sensor['lon1'], 'lat' => $sensor['lat1']];
        $end_point = ['lon' => $sensor['lon2'], 'lat' => $sensor['lat2']];
        $f = ($end_point['lon'] - $start_point['lon']) * ($boat['lat'] - $start_point['lat']) - ($boat['lon'] - $start_point['lon']) * ($end_point['lat'] - $start_point['lat']);
        $f = (float)$f;
        if($f > 0){ // 左侧
            return 1;
        }elseif($f == 0){ // 线段上
            return 2;
        }else{ // 线段右侧
            return 3;
        }
    }
    
    /**
     * 判断小船有没有绕标
     * @param $boat        小船坐标
     * @param $sensor      目标设备坐标
     * @return int         1 已经绕标    2 没有绕标
     */
    public function isAcross($boat, $sensor){
        $flag = 2; // 没绕标
        $point1 = ['lat' => $sensor['lat1'], 'lon' => $sensor['lon1']];
        $distance1 = $this->getDistance($point1, $boat);
        if($sensor['lat2']){
            $point2 = ['lat' => $sensor['lat2'], 'lon' => $sensor['lon2']];
            $distance2 = $this->getDistance($point2, $boat);
        }
        if($distance1 <= $this->cross_distance || (isset($distance2) && $distance2 <= $this->cross_distance)){
            $flag = 1; // 已绕标
        }
        return $flag;
    }
    
    /**
     * 获取两个点的中点坐标
     * @param $start_point     坐标点1
     * @param $end_point       坐标点2
     * @return mixed
     */
    public function getMiddlePoint($start_point, $end_point){
        $point['lon'] = ($start_point['lon'] + $end_point['lon']) / 2;
        $point['lat'] = ($start_point['lat'] + $end_point['lat']) / 2;
        return $point;
    }
    
    /**
     * 求等位线距离（垂直距离）
     * @param $start_points 起始坐标
     * @param $end_points  中点坐标
     * @param $sensor_location_now 船坐标
     */
    public function getIsoparmDistance($start_points, $end_points, $sensor_location_now)
    {
        $params          = $this->getLineFunction($start_points, $end_points);//求起始点终止点的直线
        $crossover_point = [];
        if ($params['flag'] == 1) {
            //求另一条直线
            $boat_k = -$params['k'];
            $boat_b = (float)$sensor_location_now['lon'] - (float)$boat_k * (float)$sensor_location_now['lat'];
            
            //求交点
            $crossover_point = $this->getCrossover(['k' => $params['k'], 'b' => $params['b']], ['k' => $boat_k, 'b' => $boat_b]);
        } elseif ($params['flag'] == 2) {
            $crossover_point['lat'] = (float)$sensor_location_now['lat'];
            $crossover_point['lon'] = $params['b'];
        } else {
            $crossover_point['lon'] = (float)$sensor_location_now['lat'];
            $crossover_point['lat'] = $params['b'];
        }
        //求等位线距离
        $distance = $this->getDistance($crossover_point, $end_points);
        return $distance;
    }
    
    /**
     * 求直线方程
     * @param $start_points 起始坐标
     * @param $end_points  中点坐标
     */
    public function getLineFunction($start_points, $end_points)
    {
        //y=$a*$x+$b
        //flag 1 ,正常直线  2垂直于y轴(lon)  3垂直于x轴(lat)
        if (((float)$start_points['lon'] - (float)$end_points['lon']) == 0) {
            return ['k' => 0, 'b' => (float)$start_points['lon'], 'flag' => 2];
        }
        if (((float)$start_points['lat'] - (float)$end_points['lat']) == 0) {
            return ['k' => 0, 'b' => (float)$start_points['lat'], 'flag' => 3];
        }
        $a = ((float)$start_points['lon'] - (float)$end_points['lon']) / ((float)$start_points['lat'] - (float)$end_points['lat']);
        $b = (float)$start_points['lon'] - $a * (float)$start_points['lat'];
        return ['k' => $a, 'b' => $b, 'flag' => 1];
    }
    
    /**
     * 求两直线交点
     * @param $line1 直线1参数数组
     * @param $line2  直线2参数数组
     * $line1=['k'=>1,'b'=>2]
     */
    public function getCrossover($line1, $line2)
    {
        //求交点
        $x = ($line2['b'] - $line1['b']) / ($line1['k'] - $line2['k']);
        $y = $line1['k'] * $x + $line1['b'];
        return ['lat' => $x, 'lon' => $y];
    }
    
    /**
     * 距离计算（米）
     * @param $point1 浮标位置、船位置
     * @param $point2
     * $point1:[lat=>11,lon=>22]
     */
    public function getDistance($point1, $point2)
    {
//        $point1 = ['lon' => '118.83169', 'lat' => '31.949992'];
//        $point2 = ['lon' => '118.833092', 'lat' => '31.948357'];
        // 将角度转为弧度
        $radLat1  = deg2rad((float)$point1['lat']); //deg2rad()函数将角度转换为弧度
        $radLat2  = deg2rad((float)$point2['lat']);
        $radLng1  = deg2rad((float)$point1['lon']);
        $radLng2  = deg2rad((float)$point2['lon']);
        $a        = $radLat1 - $radLat2;
        $b        = $radLng1 - $radLng2;
        $distance = 2 * asin(sqrt(pow(sin($a / 2), 2) + cos($radLat1) * cos($radLat2) * pow(sin($b / 2), 2))) * 6378.137 * 1000;
        return $distance;
    }
    
    /**
     * 根据当前标和目标标，获取到目标标的距离
     * @param $new_point   组装好的新的训练赛相关数组
     * @return int         距离（米）
     */
    public function getLastDistance($new_point, $boat_location){
        if($new_point['dmd_now_biao2'] && $new_point['dmd_next_biao2']){ // 当前标和目标都是双标
            // 当前标的中点
            $now_point1 = json_decode($this->redis->get($new_point['dmd_now_biao1_sid']), true);
            $now_start_point = ['lon' => $now_point1['lon'], 'lat' => $now_point1['lat']];
            $now_point2 = json_decode($this->redis->get($new_point['dmd_now_biao2_sid']), true);
            $now_end_point = ['lon' => $now_point2['lon'], 'lat' => $now_point2['lat']];
            $now_middlePoint = $this->getMiddlePoint($now_start_point, $now_end_point);
        
            // 目标设备的中点
            $next_point1 = json_decode($this->redis->get($new_point['dmd_next_biao1_sid']), true);
            $next_start_point = ['lon' => $next_point1['lon'], 'lat' => $next_point1['lat']];
            $next_point2 = json_decode($this->redis->get($new_point['dmd_next_biao2_sid']), true);
            $next_end_point = ['lon' => $next_point2['lon'], 'lat' => $next_point2['lat']];
            $next_middlePoint = $this->getMiddlePoint($next_start_point, $next_end_point);
        
            $distance = $this->getIsoparmDistance($now_middlePoint, $next_middlePoint, $boat_location);
        }elseif($new_point['dmd_now_biao2'] && !$new_point['dmd_next_biao2']){ // 双标到单标
            // 当前标的中点
            $now_point1 = json_decode($this->redis->get($new_point['dmd_now_biao1_sid']), true);
            $now_start_point = ['lon' => $now_point1['lon'], 'lat' => $now_point1['lat']];
            $now_point2 = json_decode($this->redis->get($new_point['dmd_now_biao2_sid']), true);
            $now_end_point = ['lon' => $now_point2['lon'], 'lat' => $now_point2['lat']];
            $now_middlePoint = $this->getMiddlePoint($now_start_point, $now_end_point);
        
            // 目标设备点
            $next_point1 = json_decode($this->redis->get($new_point['dmd_next_biao1_sid']), true);
            $next_start_point = ['lon' => $next_point1['lon'], 'lat' => $next_point1['lat']];
        
            $distance = $this->getIsoparmDistance($now_middlePoint, $next_start_point, $boat_location);
        }elseif(!$new_point['dmd_now_biao2'] && $new_point['dmd_next_biao2']){ // 单标到双标
            // 当前标
            $now_point1 = json_decode($this->redis->get($new_point['dmd_now_biao1_sid']), true);
            $now_start_point = ['lon' => $now_point1['lon'], 'lat' => $now_point1['lat']];
        
            // 目标设备中点
            $next_point1 = json_decode($this->redis->get($new_point['dmd_next_biao1_sid']), true);
            $next_start_point = ['lon' => $next_point1['lon'], 'lat' => $next_point1['lat']];
            $next_point2 = json_decode($this->redis->get($new_point['dmd_next_biao2_sid']), true);
            $next_end_point = ['lon' => $next_point2['lon'], 'lat' => $next_point2['lat']];
            $next_middlePoint = $this->getMiddlePoint($next_start_point, $next_end_point);
        
            $distance = $this->getIsoparmDistance($now_start_point, $next_middlePoint, $boat_location);
        }else{ // 单标到单标
            // 当前标
            $now_point1 = json_decode($this->redis->get($new_point['dmd_now_biao1_sid']), true);
            $now_start_point = ['lon' => $now_point1['lon'], 'lat' => $now_point1['lat']];
            // 目标设备点
            $next_point1 = json_decode($this->redis->get($new_point['dmd_next_biao1_sid']), true);
            $next_start_point = ['lon' => $next_point1['lon'], 'lat' => $next_point1['lat']];
        
            $distance = $this->getIsoparmDistance($now_start_point, $next_start_point, $boat_location);
        }
        return $distance;
    }
    
    /**
     * 求船角度
     * @param $sensor_location_now 船现在位置
     * @param $sensor_location 船之前位置
     * @param $start_points 船现在位置
     * @param $end_points 船之前位置
     */
    public function getAngle($sensor_location_now, $sensor_location, $start_points, $end_points)
    {
        //先计算船直线和启航线直线
        $params_boat     = $this->getLineFunction($sensor_location_now, $sensor_location);
        $params          = $this->getLineFunction($start_points, $end_points);
        $crossover_point = [];
        //求角度
        $to_start_angle = '';
        //flag 1 ,正常直线  2垂直于y轴  3垂直于x轴
        //tanα   =|(k2 - k1) / (1 + k1k2) |
        if ($params['flag'] == 1) {
            if ($params_boat['flag'] == 1) {
                $to_start_angle = 90 - atan(abs(($params_boat['k'] - $params['k']) / (1 + $params_boat['k'] * $params['k']))) / pi() * 180;
            } elseif ($params_boat['flag'] == 2) {
                $to_start_angle = 90 - atan(abs($params['k'])) / pi() * 180;
            } else {
                $to_start_angle = 90 - atan(abs($params['k'])) / pi() * 180;
            }
        } elseif ($params['flag'] == 2) {
            if ($params_boat['flag'] == 1) {
                $to_start_angle = 90 - atan(abs($params_boat['k'])) / pi() * 180;
            } else {
                $to_start_angle = 90;
            }
        } else {
            if ($params_boat['flag'] == 1) {
                $to_start_angle = 90 - atan(abs($params_boat['k'])) / pi() * 180;
            } else {
                $to_start_angle = 90;
            }
        }
        $to_start_angle = number_format((float)$to_start_angle, 2);
//        return $to_start_angle;
        //起始点在1 3 象限则右
        if ($sensor_location['lat'] < $this->temp_start_cross_points['lat'] && $sensor_location['lon'] < $this->temp_start_cross_points['lon']
            || $sensor_location['lat'] > $this->temp_start_cross_points['lat'] && $sensor_location['lon'] > $this->temp_start_cross_points['lon']
        ) {
            return 'S' . $to_start_angle;
        } else {
            return 'R' . $to_start_angle;
        }
    }
    
    /**
     * 判断是否相交，并且在线段上
     * @param $start_points 起始坐标
     * @param $end_points  终点坐标
     * @param $sensor_location_now 船当前坐标
     * @param $sensor_location 船只之前坐标
     * @param $type 要判断的线的类型 1起始线 2终止线
     */
    public function judgeInLine($start_points, $end_points, $sensor_location_now, $sensor_location, $type)
    {
        //求另一条直线
        if (!array_diff($sensor_location_now, $sensor_location) && !array_diff($sensor_location, $sensor_location_now)) {
            return 0;//未相交
        }
        if ($sensor_location_now['lon'] == $sensor_location['lon'] && $sensor_location_now['lat'] == $sensor_location['lat']) {
            return 0;//未相交
        }
        $params = $this->getLineFunction($start_points, $end_points);//求起始点终止点的直线
        
        $params_boat     = $this->getLineFunction($sensor_location_now, $sensor_location);//求起始点终止点的直线
        $crossover_point = [];
        //两条正常直线
        if ($params['flag'] == 1) {
            if ($params_boat['flag'] == 1) {
                $boat_k = $params_boat['k'];
                $boat_b = $params_boat['b'];
                if ($boat_k == $params['k']) {
                    return 0;//未相交
                }
                $crossover_point = $this->getCrossover(['k' => $params['k'], 'b' => $params['b']], ['k' => $boat_k, 'b' => $boat_b]);
            } elseif ($params_boat['flag'] == 2) {
                $crossover_point['lat'] = ($params_boat['b'] - $params['b']) / $params['k'];
                $crossover_point['lon'] = $params_boat['b'];
            } else {
                $crossover_point['lat'] = $params_boat['b'];
                $crossover_point['lon'] = $params_boat['b'] * $params['k'] + $params['b'];
            }
        } elseif ($params['flag'] == 2) {
            if ($params_boat['flag'] == 1) {
                $crossover_point['lat'] = ($params['b'] - $params_boat['b']) / $params_boat['k'];
                $crossover_point['lon'] = $params['b'];
            } elseif ($params_boat['flag'] == 2) {
                return 0;
            } else {
                $crossover_point['lat'] = $params_boat['b'];
                $crossover_point['lon'] = $params['b'];
            }
        } else {
            if ($params_boat['flag'] == 1) {
                $crossover_point['lat'] = $params['b'];
                $crossover_point['lon'] = $params['b'] * $params_boat['k'] + $params_boat['b'];
            } elseif ($params_boat['flag'] == 2) {
                $crossover_point['lat'] = $params['b'];
                $crossover_point['lon'] = $params_boat['b'];
            } else {
                return 0;
            }
        }
        
        //判断点是否在线段上
        $PAx = $start_points['lat'];
        $PAy = $start_points['lon'];
        $PBx = $end_points['lat'];
        $PBy = $end_points['lon'];
        $PCx = $sensor_location_now['lat'];
        $PCy = $sensor_location_now['lon'];
        $PDx = $sensor_location['lat'];
        $PDy = $sensor_location['lon'];
        $x   = $crossover_point['lat'];
        $y   = $crossover_point['lon'];
        if ((min($PAx, $PBx) <= $x && $x <= max($PAx, $PBx) && min($PAy, $PBy) <= $y && $y <= max($PAy, $PBy)) && (min($PCx, $PDx) <= $x && $x <= max($PCx, $PDx) && min($PCy, $PDy) <= $y && $y <= max($PCy, $PDy))) {
            if ($type == 1) {
                $this->temp_start_cross_points = $crossover_point;
            }
            return 1;//相交在线上
        } else {
            return 0;//未相交
        }
    }
    
    /**
     * 求当前船的速度
     * @param $location          当前坐标
     * @param $location_last     上一秒坐标
     * @return float|string
     */
    public function getSpeed($location, $location_last)
    {
        $distance = $this->getDistance($location_last, $location);
        $speed    = 1.94386 * abs((float)$distance / 1);
        $speed    = number_format($speed, 2);
        return $speed;
    }
    
    /**
     * 求船在经过起始线时在线段的位置
     * @param $start_points 启航线起始点
     * @param $end_points 启航线zhongdian
     */
    public function getLocation($start_points, $end_points)
    {
        //启航线长度
        $line_distance = $this->getDistance($start_points, $end_points);
        //交点到启航线左点长度
        $cross_distance = $this->getDistance($start_points, $this->temp_start_cross_points);
        $half           = $line_distance / 2;
        $D_value        = $cross_distance - $half;
        $abs            = abs($D_value);
        if ($D_value > 0) {
            $abs = $line_distance - $cross_distance;
            return 'R' . round($abs / $half * 100) . "%";
        } else {
            return 'L' . round($abs / $half * 100) . "%";
        }
    }
    
    /**
     * 获取距离终点的距离
     * @param $boat_location     小船坐标
     * @param $sensor_arr        设备数组
     * @param $biao_name         剩余标名
     * @return int
     */
    public function getFinishDistance($boat_location, $sensor_arr, $biao_name){
//        $biao_name = 'FL/FR';
        $arr = explode('-', $biao_name);
        $arr = array_filter($arr);
        $arr_num = count($arr);
        $finish_distance = 0; // 距离终点距离
        if($arr_num != 0){
            // 如果是最后一个标
            if($arr_num == 1){
                // 终点线段中点坐标
                $FL = json_decode($this->redis->get($sensor_arr['FL']), true);
                $FR = json_decode($this->redis->get($sensor_arr['FR']), true);
                $_middlePoint = $this->getMiddlePoint($FL, $FR);
                
                // 距终点距离
                $finish_distance = $this->getDistance($_middlePoint, $boat_location);
            }else{
                for($i = 0; $i < $arr_num - 1; $i++){
                    if(strpos($arr[$i], '/') !== false && strpos($arr[$i+1], '/') !== false){ // 双-双
                        $_start_arr = explode('/', $arr[$i]);
                        $_end_arr = explode('/', $arr[$i+1]);
                        // 第一个设备中点
                        $_start1 = json_decode($this->redis->get($sensor_arr[$_start_arr[0]]), true);
                        $_start2 = json_decode($this->redis->get($sensor_arr[$_start_arr[1]]), true);
                        $start_middlePoint = $this->getMiddlePoint($_start1, $_start2);
                        
                        // 下个设备中点
                        $_end1 = json_decode($this->redis->get($sensor_arr[$_end_arr[0]]), true);
                        $_end2 = json_decode($this->redis->get($sensor_arr[$_end_arr[1]]), true);
                        $end_middlePoint = $this->getMiddlePoint($_end1, $_end2);
                        
                        $finish_distance += $this->getDistance($start_middlePoint, $end_middlePoint);
                    }elseif(strpos($arr[$i], '/') !== false && strpos($arr[$i+1], '/') === false){ // 双-单
                        $_start_arr = explode('/', $arr[$i]);
                        // 第一个设备中点
                        $_start1 = json_decode($this->redis->get($sensor_arr[$_start_arr[0]]), true);
                        $_start2 = json_decode($this->redis->get($sensor_arr[$_start_arr[1]]), true);
                        $start_middlePoint = $this->getMiddlePoint($_start1, $_start2);
                        
                        // 下个设备
                        $end = json_decode($this->redis->get($sensor_arr[$arr[$i+1]]), true);
                        
                        $finish_distance += $this->getDistance($start_middlePoint, $end);
                    }elseif(strpos($arr[$i], '/') === false && strpos($arr[$i+1], '/') !== false){ // 单-双
                        $_end_arr = explode('/', $arr[$i+1]);
                        
                        // 第一个设备中点
                        $start = json_decode($this->redis->get($sensor_arr[$arr[$i]]), true);
                        
                        // 下个设备
                        $_end1 = json_decode($this->redis->get($sensor_arr[$_end_arr[0]]), true);
                        $_end2 = json_decode($this->redis->get($sensor_arr[$_end_arr[1]]), true);
                        $end_middlePoint = $this->getMiddlePoint($_end1, $_end2);
                        
                        $finish_distance += $this->getDistance($start, $end_middlePoint);
                    }else{ // 单-单
                        // 第一个设备
                        $start = json_decode($this->redis->get($sensor_arr[$arr[$i]]), true);
                        
                        // 下个设备
                        $end = json_decode($this->redis->get($sensor_arr[$arr[$i+1]]), true);
                        
                        $finish_distance += $this->getDistance($start, $end);
                    }
                }
    
                if($arr[0] != 'SR/SL' && $arr[0] != 'SL/SR'){ // 进行中，需要加上我距离下个标的距离
                    if(strpos($arr[0], '/') !== false){ // 下一个双标
                        $_next = explode('/', $arr[0]);
                        $_next1 = json_decode($this->redis->get($sensor_arr[$_next[0]]), true);
                        $_next2 = json_decode($this->redis->get($sensor_arr[$_next[1]]), true);
                        $_next_middlePoint = $this->getMiddlePoint($_next1, $_next2);
                        $finish_distance += $this->getDistance($_next_middlePoint, $boat_location);
                    }else{
                        $_next = json_decode($this->redis->get($sensor_arr[$arr[0]]), true);
                        $finish_distance += $this->getDistance($_next, $boat_location);
                    }
                }
                
            }
            
        }
        
        return $finish_distance;
    }
}